package com.xxxx.server.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxxx.server.exceptions.MyException;
import com.xxxx.server.mapper.AdminRoleMapper;
import com.xxxx.server.mapper.MenuMapper;
import com.xxxx.server.mapper.MenuRoleMapper;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.Menu;
import com.xxxx.server.pojo.Role;
import com.xxxx.server.service.IMenuService;
import com.xxxx.server.utils.AnyUtil;
import com.xxxx.server.utils.AssertUtil;
import com.xzl.tool.util.RespBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhoubin
 * @since 2020-10-15
 */

@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {

	@Resource
	private MenuMapper menuMapper;
	@Resource
	private RedisTemplate redisTemplate;
	@Resource
	private MenuRoleMapper menuRoleMapper;
	@Resource
	private AdminRoleMapper adminRoleMapper;
	/**
	 * 通过用户id获取菜单列表
	 *
	 * @return
	 *
	 */
	@Override
	public List<Menu> getMenusByAdminId() {
		Admin admin = (Admin) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//		//获取Id
		List<Role> roles = admin.getRoles();
		Integer adminId = admin.getId();
		StringBuffer stringBuffer = new StringBuffer();
		List<Integer> rids = new LinkedList<>();
		for (Role role : roles) {
			rids.add(role.getId());
			stringBuffer = stringBuffer.append("_"+role.getName());
		}
		//从redis中获取菜单缓存数据
//		ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
		//查询缓存中是否有数据
//		List<Menu> menus = (List<Menu>) valueOperations.get("menu" + stringBuffer.toString());
//		//如果没数据，数据库中查询，并设置到缓存中
//		if (CollectionUtils.isEmpty(menus)){
		List<Menu> menus = menuMapper.getMenusByAdminId(rids,stringBuffer.toString());
//			valueOperations.set("menu"+stringBuffer,menus);
//		}
		return menus;
	}


	/**
	 * 查询所有菜单及对应角色
	 *
	 * @return
	 */
	@Override
	public List<Menu> getMenusWithRoles() {
		return menuMapper.getMenusWithRoles();
	}

	/**
	 * 根据角色id查询菜单
	 * @param rid
	 * @return 角色对应的菜单集合
	 */
	@Override
	public List<Menu> getMenusByRoleId(Integer rid) {
		AssertUtil.isTrue(null==rid,"角色id不能为空");
		//获得一级菜单
		List<Menu> menus = menuMapper.selectMenusByRoleId(rid,1);
		AssertUtil.isTrue(null==menus || menus.size()<1,"该角色暂无权限");
		//遍历一级菜单
		menus.forEach(t->{
			//查询一级菜单下的子菜单
			List<Menu> children = menuMapper.selectMenusByRoleId(rid, t.getId());
			t.setChildren(children);
		});
		System.out.println(menus);
		//返回菜单
		return menus;
	}

	/**
	 * 查询所有菜单
	 *
	 * @return 菜单列表
	 */
	@Override
	public List<Menu> getMenusAll() {
		List<Menu> menusByParentId = menuMapper.getMenusByParentId(0);
		return menusByParentId;
	}

	/**
	 * 根据角色id查询所有权限id
	 *
	 * @param rid
	 * @return
	 */
	@Override
	public List<Integer> getMidsByRid(Integer rid) {
		return menuRoleMapper.selectMenusIdsByRoleId(rid);
	}

	/**
	 * 修改角色访问资源
	 * @param rid
	 * @param mids
	 * @return
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public RespBean updateMenuRole(Integer rid, Integer[] mids) {
		AssertUtil.isTrue(null==rid,"角色id不能为空");
		AssertUtil.isTrue(null==menuMapper.selectById(rid),"该角色不存在");
		Integer addCount=0;
		//查询该角色对应的所有权限
		Integer count = menuRoleMapper.getCountByRoleId(rid);
		//根据角色id删除，返回删除条数
		Integer  delMenus = menuRoleMapper.deleteByRoleId(rid);
		AssertUtil.isTrue(delMenus!=count,"修改失败");
		//判断菜单id
		if (null==mids||mids.length==0){
			return RespBean.success("修改成功");
		}else {

			 addCount = menuRoleMapper.insertMenuRole(rid, mids);
		}
		AssertUtil.isTrue(addCount!=mids.length,"修改失败");
		//获取拥有该角色的adminId集合
		List<Integer> adminIdList = adminRoleMapper.selectAdminIdsByRoleId(rid);
		//清空redis中的缓存
		adminIdList.forEach(t->{
			redisTemplate.delete("menu_"+t);
		});
		AnyUtil.updRedisMenu();
		return RespBean.success("修改成功,权限会在相关操作员重新登录后刷新");
	}

	/**
	 * 新增菜单
	 * 菜单新增的同时，默认关联系统管理员，使用了存储过程操作整段语句
	 * @param menu
	 * @return
	 */
	@Override
	@Transactional
	public void insertMenu(Menu menu) {
		menuMapper.insertMenu(menu);
		if (menu.getResult() < 1) throw new MyException("新增失败！请重新添加！");
		//更新菜单时，也许更新redis中用户对应的菜单
		AnyUtil.updRedisMenu();
	}

	/**
	 * 传menu对象是为了使用存储过程，进行删除
	 * 由于删除menu时候，需要检测该menu下是否还有子menu，
	 * 所以需要再查询一遍是否包含做数据保护
	 * @param id
	 */
	@Override
	@Transactional
	public void delMenuById(Integer id) {
		Menu menu = new Menu();
		menu.setId(id);
		menuMapper.delMenuById(menu);
		if (menu.getResult() == -2){
			throw new MyException("该菜单下还有子菜单！请勿删除！");
		}else if(menu.getResult() == 0){
			throw new MyException("未找到您选中的菜单，请刷新数据 ！");
		}
		//更新菜单时，也许更新redis中用户对应的菜单
		AnyUtil.updRedisMenu();
	}

	/**
	 * 修改menu，返回当前menu
	 * @param menu
	 * @return
	 */
	@Override
	@Transactional
	public void updMenu(Menu menu) {
		int i = menuMapper.updMenu(menu);
		if(i < 1) throw new MyException("修改失败，请重新修改！");
		//更新菜单时，也许更新redis中用户对应的菜单
		AnyUtil.updRedisMenu();
	}

	@Override
	public void updMenuEnambled(Integer menuId, Boolean enabled) {
		menuMapper.updMenuEnambled(menuId,enabled);
		AnyUtil.updRedisMenu();
	}

}
